#include "LoopControlInfoManager.h"

#include <fstream>
#include <time.h>


LoopControlInfoManager::LoopControlInfoManager() : mpath(OFFLINE_COMMAND_CONFIG) {

}

LoopControlInfoManager::~LoopControlInfoManager() {
    clear();
}


bool LoopControlInfoManager::load(const DateTimeUtility::ClockTime_t& timeOfDay) {
    std::string fileName = OFFLINE_COMMAND_CONFIG;
    myearMonthString.clear();

    std::time_t seconds = DateTimeUtility::toTime_t(timeOfDay);
    DateTimeUtility::toYearMouthString(DateTimeUtility::toTm(seconds), myearMonthString);
    fileName.append(myearMonthString);
    std::filesystem::path path(fileName);

    std::ifstream inputFileStream(path, std::ios::in);
    bool result = false;
    LoopControlInfo* pControlInfo = nullptr, *clonedControlInfo = nullptr, *pEnd;
    if(inputFileStream) {
        result = true;
        std::uintmax_t size = std::filesystem::file_size(path);
        char buffer[size];
        inputFileStream.read(buffer, sizeof (buffer));
        pEnd = reinterpret_cast <LoopControlInfo*>(buffer + size);
        for (pControlInfo = reinterpret_cast<LoopControlInfo*> (buffer); pControlInfo != pEnd; pControlInfo = pControlInfo->next()) {

            clonedControlInfo = new(pControlInfo->length) LoopControlInfo(*pControlInfo);
            mloopControlInfos.emplace_back(clonedControlInfo, LoopControlInfo::releaseMemory);
        }
    }

    inputFileStream.close();
    return result;
}


bool LoopControlInfoManager::load(const DateTimeUtility::ClockTime_t& timeOfDay, const bool loadPrevInfoOfDay, LoopControlInfoList& loopControlInfos) {
    DateTimeUtility::ClockTime_t beginOfDay = timeOfDay;

    beginOfDay = timeOfDay - timeOfDay % DateTimeUtility::TICK_COUNT_OF_DAY;

    bool haveControlInfoToday{false}, first{true};//
    const LoopControlInfoPtr* pPrevLoopControlInfoPtr = nullptr;
    const DateTimeUtility::ClockTime_t endOfDay = timeOfDay - timeOfDay % DateTimeUtility::TICK_COUNT_OF_DAY + DateTimeUtility::TICK_COUNT_OF_DAY;

    LoopControlInfoList::iterator end = mloopControlInfos.end();
    for (LoopControlInfoList::iterator iterator = mloopControlInfos.begin(); iterator != end; ++iterator) {
        const LoopControlInfoPtr& pControlInfo = *iterator;
        if (beginOfDay <= pControlInfo->beginTime && endOfDay > pControlInfo->beginTime){
            haveControlInfoToday = true;
            if (timeOfDay <= pControlInfo->beginTime) {
                if (loadPrevInfoOfDay && first){
                    first = false;
                    if (nullptr != pPrevLoopControlInfoPtr){
                         loopControlInfos.emplace_back(*pPrevLoopControlInfoPtr);
                    }

                }
                loopControlInfos.emplace_back(pControlInfo);
            }
        }else if (endOfDay <= pControlInfo->beginTime){
            break;
        }

        pPrevLoopControlInfoPtr = &pControlInfo;
    }

    if (loadPrevInfoOfDay && haveControlInfoToday && pPrevLoopControlInfoPtr &&loopControlInfos.empty()){
        loopControlInfos.emplace_back(*pPrevLoopControlInfoPtr);
    }

    return true;
}



bool LoopControlInfoManager::save(const DateTimeUtility::ClockTime_t& timeOfDay, LoopControlInfoList& loopControlInfos) {
    std::string dateString;

    std::time_t seconds = DateTimeUtility::toTime_t(timeOfDay);
    DateTimeUtility::toYearMouthString(DateTimeUtility::toTm(seconds), dateString);

    return save(dateString, loopControlInfos);
}



bool LoopControlInfoManager::save(const std::string& timeOfDay, LoopControlInfoList& loopControlInfos) {
    std::string fileName = OFFLINE_COMMAND_CONFIG + timeOfDay;

    std::filesystem::path path(fileName);
    std::ofstream outputFileStream(path,  std::ios::out);

    LoopControlInfoList::iterator end = loopControlInfos.end();
    for (LoopControlInfoList::iterator iterator = loopControlInfos.begin(); iterator != end; ++iterator) {
        const LoopControlInfoPtr& pControlInfo = *iterator;
        outputFileStream.write(reinterpret_cast <const char*>(&*pControlInfo), LoopControlInfo::computeByteSize(pControlInfo->length));
    }
    outputFileStream.close();
    return true;

}



LoopControlInfoPtr LoopControlInfoManager::locateLoopControlInfo(const DateTimeUtility::ClockTime_t& time, const int32_t offset) {
    LoopControlInfoPtr loopControlInfoPtr;

    LoopControlInfoList loopControlInfoList = getLoopControlInfos(time);
    const LoopControlInfoList::iterator end = loopControlInfoList.end();
    LoopControlInfoList::iterator resultIterator = end;
    for (LoopControlInfoList::iterator iterator = loopControlInfoList.begin(); iterator != end; ++iterator) {
        const LoopControlInfoPtr& pControlInfo = *iterator;

        if (pControlInfo->beginTime > time) {
            resultIterator = iterator;
            break;
        }
    }

    if (end != resultIterator) {
        std::advance(resultIterator, offset);
        if (end != resultIterator) {
            loopControlInfoPtr = *resultIterator;
        }
    }

    return loopControlInfoPtr;
}



bool LoopControlInfoManager::clear() {
    LOG_DEDUG("clear offline command");
//    LoopControlInfoList::iterator end = mloopControlInfos.end();
//    for (LoopControlInfoList::iterator iterator = mloopControlInfos.begin(); iterator != end; ++iterator) {
//        LoopControlInfo::releaseMemory(&**iterator);
//    }

    myearMonthString.clear();

    mloopControlInfos.clear();
//    std::filesystem::remove(mpath);

    return true;
}








